package com.moody.calculator;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.moody.hibernate.domain.ReportData;
import com.moody.init.ReportModelInit;

/*
 * Copyright © Moody analytics   
 *
 * @Title: FinanVerify.java 
 * @Package： com.moody.calculator 
 * @author： Fuqiang Wang
 * @Description: 金融同业报表检验   
 * @date： 2012-2-28 下午3:17:51
 * @Modified by: Fuqiang Wang 
 * @version V1.0   
 */

public class FinanVerify {
	private static final Logger log = LoggerFactory
			.getLogger(FinanVerify.class);
	private List<ReportData> reportDataList; // 某期报表的list
	private Map<String, Double> valueMap = new HashMap<String, Double>(); // 存储某期报表所有填写的数据项
	private Map<String,String> nameMap;
	private Map<String,String> checkMap;
	private List<String> resultList = new ArrayList<String>(); // 最终的返回结果

	public FinanVerify(List<ReportData> reportDataList) {
		this.reportDataList = reportDataList;
		nameMap = ReportModelInit.getInstance().getDisplayNameMap();
		checkMap = new HashMap<String,String>();

		initCheckMap();
	}

	public void loadData() {
		if (reportDataList != null) {
			for (ReportData rd : reportDataList) {
				valueMap.put(rd.getReportItemNo(), rd.getItemValue());
			}
		}
	}
	
	// 判断double类型是否为0
	public Boolean isZero(Double data) {
		if (data > 10E-6 || data < -(10E-6))
			return false;
		else
			return true;
	}

	public List<String> getResultList() {
		// 结果为空 重新检验
		if (resultList == null || resultList.size() == 0) {
			formVerify();
		}
		return resultList;
	}

	// 报表检验
	public void formVerify() {
		FinanVerify pv = new FinanVerify(reportDataList);
		pv.loadData();
		Method[] methods = FinanVerify.class.getDeclaredMethods();
		for (Method method : methods) {
			String name = method.getName();
			// 抽取所有以calculate的方法，表示是计算公式
			if (name.startsWith("verify")) {
				try {
					if (method.invoke(pv) != null)
						resultList.add(method.invoke(pv).toString());
				} catch (Exception e) {
					log.error("该项计算有误", e);
				}
			}
		}
		
		resultList.addAll(pv.checkBalance());
	}
	
	// 完整性检验
	public String verify001() {
		Boolean flag = true; // 是否完整
		for (ReportData rd : reportDataList) {
			if (rd.getItemValue() == null && !rd.getReportItemNo().startsWith("FFR")) {
				flag = false;
				log.info(""+rd.getDisplayName()+" "+rd.getReportItemNo());
			}
		}

		if (flag) {
			return null;
		} else {
			return "报表完整性检查:报表不完整";
		}
	}
	
//	// 报表是否平衡
//	public String verify002() {
//		Double FBS044 = valueMap.get("FBS044");
//		Double FBS084 = valueMap.get("FBS084");
//		Double FBS092 = valueMap.get("FBS092");	
//
//		if (FBS044 != null && FBS084 != null && FBS092 != null && isZero(FBS044 - FBS084 - FBS092)) {
//			return null;
//		} else {
//			return "资产总计  ≠ 负债合计 + 所有者权益合计";
//		}
//	}
	
	//流动资产合计 < 0 
	public String verify003() {
		Double FBS023 = valueMap.get("FBS023");

		if (FBS023 == null || FBS023 < 0)
			return "流动资产合计缺失或者流动资产合计 < 0 或为空值";
		else
			return null;
	}
	
	//长期资产合计 < 0 
	public String verify004() {
		Double FBS094 = valueMap.get("FBS094");

		if (FBS094 == null || FBS094 < 0)
			return "长期资产合计缺失或者长期资产合计 < 0 或为空值";
		else
			return null;
	}
	
	//其他资产合计 < 0 
	public String verify005() {
		Double FBS095 = valueMap.get("FBS095");

		if (FBS095 == null || FBS095 < 0)
			return "其他资产合计缺失或其他资产合计 < 0 或为空值";
		else
			return null;
	}
	
	//流动负债合计 < 0 
	public String verify006() {
		Double FBS071 = valueMap.get("FBS071");

		if (FBS071 == null || FBS071 < 0)
			return "流动负债合计缺失或流动负债合计  < 0 或为空值";
		else
			return null;
	}
	
	//长期负债合计 < 0 
	public String verify007() {
		Double FBS083 = valueMap.get("FBS083");

		if (FBS083 == null || FBS083 < 0)
			return "长期负债合计缺失或长期负债合计  < 0 或为空值";
		else
			return null;
	}
	
	//所有者权益合计 < 0 
	public String verify008() {
		Double FBS092 = valueMap.get("FBS092");

		if (FBS092 == null || FBS092 < 0)
			return "所有者权益合计缺失或所有者权益合计  < 0 或为空值";
		else
			return null;
	}
	
//	//资产总计 ≠ 流动资产合计 + 长期资产合计 + 其他资产合计;
//	public String verify009(){
//		Double FBS044 = valueMap.get("FBS044");
//		Double FBS023 = valueMap.get("FBS023");
//		Double FBS094 = valueMap.get("FBS094");
//		Double FBS095 = valueMap.get("FBS095");
//		
//		if(FBS044 != null && FBS023 != null && FBS094 != null && FBS095 != null 
//				&& !isZero(FBS044 - FBS023 - FBS094 - FBS095))
//			return "资产总计 ≠ 流动资产合计 + 长期资产合计 + 其他资产合计";
//		else
//			return null;
//	}
//
//	//负债合计 ≠ 流动负债合计 + 长期负债合计;
//	public String verify010(){
//		Double FBS084 = valueMap.get("FBS084");
//		Double FBS071 = valueMap.get("FBS071");
//		Double FBS083 = valueMap.get("FBS083");
//	
//		if(FBS084 != null && FBS071 != null && FBS083 != null 
//				&& !isZero(FBS084 - FBS071 - FBS083))
//			return "负债合计 ≠ 流动负债合计 + 长期负债合计";
//		else
//			return null;
//	}
//	
//	//负债及所有者权益总计  ≠ 负债合计 + 所有者权益合计
//	public String verify011(){
//		Double FBS093 = valueMap.get("FBS093");
//		Double FBS084 = valueMap.get("FBS084");
//		Double FBS092 = valueMap.get("FBS092");
//		
//		if(FBS093 != null && FBS084 != null && FBS092 != null 
//				&& !isZero(FBS093 - FBS084 - FBS092))
//			return "负债及所有者权益总计  ≠ 负债合计 + 所有者权益合计";
//		else
//			return null;
//	}
	
	public List<String> checkBalance(){
		DecimalFormat df = new DecimalFormat("###,##0.00");
		Set<String> keySet = checkMap.keySet();
		for(String sumKey :keySet){
			if(!valueMap.containsKey(sumKey)) continue;
//			log.info("总和：" + valueMap.get(sumKey) +"("+sumKey+")");
			String[] itemArray = checkMap.get(sumKey).split(",");
			double res = 0;
			for(String itemKey : itemArray){
				double value = 0;
				if(itemKey.substring(0, 1).equals("-")) value =  valueMap.get(itemKey.substring(1)) * -1;
				else value = valueMap.get(itemKey);
				res += value; 
//				log.info("———— " + value + "("+itemKey+")");
			}
			
			
			res = valueMap.get(sumKey) - res;
			
			BigDecimal bd = new BigDecimal(res);
			res = bd.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
			
			if(Math.abs(res) > 10E-6){
//				log.info("————差额： " + res);
				String itemList = "";
				if(itemArray.length == 1){
					itemList = nameMap.get(itemArray[0]);
				}
				else{
					itemList = "(";
					for(String itemKey : itemArray){
						if(itemKey.substring(0, 1).equals("-")) {
							if(itemList.length() > 1) itemList += " -";
							itemList += " " + nameMap.get(itemKey.substring(1));
						}
						else {
							if(itemList.length() > 1) itemList += " +";
							itemList += " " + nameMap.get(itemKey);
						}
					}
					itemList += ")";
				}
				
				String title = null;
				if(sumKey.contains("BS")) title = "资产负债表：";
				else if(sumKey.contains("EIS")) title = "利润表：";
				else if(sumKey.contains("PIS")) title = "收入支出表：";
				else if(sumKey.contains("FIS")) title = "损益表：";
				else if(sumKey.contains("CF")) title = "现金流量表：";
				resultList.add(title + nameMap.get(sumKey) +" - " + itemList +" = " + df.format(res));
				
			}
		}
		return resultList;
	}
	
	private void initCheckMap(){
		/*
		 * 金融机构
		 */
		//资产负债表
		checkMap.put("FBS023", "FBS004,FBS005,FBS007,FBS008,FBS009,FBS010,FBS011,FBS012,FBS015,FBS016,-FBS017,FBS018,FBS019,FBS020,FBS022");
		checkMap.put("FBS094", "FBS025,FBS027,-FBS028,FBS029,-FBS031,FBS034,FBS035,FBS036,FBS037,FBS038");
		checkMap.put("FBS095", "FBS040,FBS042,FBS043");
		checkMap.put("FBS044", "FBS023,FBS094,FBS095");
		checkMap.put("FBS071", "FBS048,FBS049,FBS050,FBS051,FBS053,FBS054,FBS055,FBS056,FBS058,FBS059,FBS060,FBS061,FBS062,FBS064,FBS065,FBS066,FBS067,FBS068,FBS069,FBS070");
		checkMap.put("FBS083", "FBS074,FBS075,FBS077,FBS078,FBS079,FBS080,FBS081");
		checkMap.put("FBS084", "FBS071,FBS083");
		checkMap.put("FBS092", "FBS086,FBS088,FBS089,FBS091");
		checkMap.put("FBS093", "FBS084,FBS092");
		
		//损益表
		checkMap.put("FIS010", "FIS011,FIS012,FIS013,FIS014,FIS015,FIS016");
		checkMap.put("FIS018", "FIS001,-FIS010,-FIS017");
		checkMap.put("FIS023", "FIS018,FIS019,FIS020,-FIS021,-FIS022");
		checkMap.put("FIS025", "FIS023,-FIS024");
		
		
	}

}
